package org.wizehack.mri.repo;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.bson.types.ObjectId;
import org.wizehack.mri.SFLocalizer;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;

public class MongoDBAccessPoint {
	
	private static MongoDBAccessPoint dbap = null;
	private Mongo mongo = null;
	private static DB db = null;
	private String projectName = null;
//	private static Logger logger;

	private MongoDBAccessPoint(){
		try {
			this.mongo = new Mongo();
//			PropertyConfigurator.configure("./config/log4j.properties");
//			logger = Logger.getLogger(SFLocalizer.class);

		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public synchronized static MongoDBAccessPoint getInstance(){
		
		if(dbap == null)
			dbap = new MongoDBAccessPoint();
		
		return dbap;
		
	}

	public void createDataBase(String name) {
		//add the validation code of input name
		this.projectName = name;
		this.db = this.mongo.getDB("mri_" + this.projectName + "_db");
	}

	private DBCollection source_file;
	private DBCollection source_code;
	private DBCollection coverage;
	private DBCollection suspiciousness_code;
	private DBCollection test_result;
	
	public void useDBName(String name){
		this.projectName = name;
		this.db = this.mongo.getDB("mri_" + this.projectName + "_db");
		
		source_file = db.getCollection("source_file");
		source_code = db.getCollection("source_code");
		coverage = db.getCollection("coverage");
		test_result = db.getCollection("test_result");
		suspiciousness_code = db.getCollection("suspiciousness_code");
	}
	
	public void createSourceFile() {
		source_file = db.getCollection("source_file");
	}

	/**
	 * create a source_code collection
	 */
	public void createSourceCode() {
		source_code = db.getCollection("source_code");
	}

	public void createCoverage() {
		coverage = db.getCollection("coverage");
	}

	public void createSuspiciousness() {
		suspiciousness_code = db.getCollection("suspiciousness_code");
	}

	public void createTestResult() {
		test_result = db.getCollection("test_result");
	}

	public synchronized Object insertDataToSourceFile(String name) {
		BasicDBObject doc = new BasicDBObject();
		doc.append("name", name);
		
		source_file.insert(doc);
		
		ObjectId id = (ObjectId)doc.get( "_id" );
		
		return id;
	}

	public synchronized Object insertDataToSourceCode(String fileId, String fileName, int number, String code) {
		BasicDBObject doc = new BasicDBObject();
		doc.append("file_id", fileId);
		doc.append("file_name", fileName);
		doc.append("number", number);
		doc.append("code", code);
		
		source_code.insert(doc);
		ObjectId id = (ObjectId)doc.get( "_id" );
		
		return id;
	}

	public synchronized Object insertDataToCoverage(String fileName, String sourceCodeId, int number, String code, int testSuite,
			int testCase) {
		
		BasicDBObject doc = new BasicDBObject();
		doc.append("file_name", fileName);
		doc.append("source_code_id", sourceCodeId);
		doc.append("number", number);
		doc.append("code", code);
		doc.append("test_suite", testSuite);
		doc.append("test_case", testCase);
//		doc.append("is_covered", isCovered);

		coverage.insert(doc);

		ObjectId id = (ObjectId)doc.get( "_id" );

		return id;
	}

	public synchronized Object insertDataToSuspiciousness(String fileName, String sourceCodeId, String code, int number,
			int testSuite, double suspiciousness) {		
		
		BasicDBObject doc = new BasicDBObject();
		doc.append("file_name", fileName);
		doc.append("source_code_id", sourceCodeId);
		doc.append("number", number);
		doc.append("code", code);
		doc.append("test_suite", testSuite);
		doc.append("suspiciousness", suspiciousness);

		suspiciousness_code.insert(doc);

		ObjectId id = (ObjectId)doc.get( "_id" );

		return id;
	}

	public synchronized Object insertDataToTestResult(int testSuite, int testCase,
			boolean isPassed) {
		
		BasicDBObject doc = new BasicDBObject();
		doc.append("test_suite", testSuite);
		doc.append("test_case", testCase);
		doc.append("is_passed", isPassed);

		test_result.insert(doc);

		ObjectId id = (ObjectId)doc.get( "_id" );

		return id;
	}
	
	public void deleteDataBase(String name) {
		
		this.projectName = name;
		this.db = this.mongo.getDB("mri_" + this.projectName + "_db");
		this.db.dropDatabase();
	}
	
	public DBCursor getDocumentsFromSourceFile(){
		DBCursor cursor = source_file.find();
		return cursor;
	}
		
	public DBCursor getDocumentsFromSourceCode(){
		DBCursor cursor = source_code.find();
		return cursor;
	}
	

	public DBObject getDocumentFromSourceCode(String sourceFileName, int lineNumber) {
		BasicDBObject doc = new BasicDBObject("file_name", sourceFileName).append("number", lineNumber);
        
		DBObject dObj = source_code.findOne(doc);
//		System.out.println(dObj);
		return dObj;
	}
	
	public List<Object> getDBObjectListFromSourceCode() {
		List<Object> idList = new ArrayList<Object>();

		DBCursor cursor = getDocumentsFromCoverage();
//		idList = cursor.toArray();
		try{
			while(cursor.hasNext()){
				Object obj = cursor.next().get("source_code_id");
//				DBObject dObj = cursor.next();
				if( (idList.contains(obj) != true) )
					idList.add(obj);
			}
		} finally {
			cursor.close();
		}

		return idList;
	}
	
	public DBCursor getDocumentsFrommTestResult(){
		DBCursor cursor = test_result.find();
		return cursor;
	}
	
	public DBCursor getDocumentsFromCoverage(){
		DBCursor cursor = coverage.find();
		return cursor;
	
	}
	
	public synchronized DBCursor getDocumentsFromCoverage(String sourceCodeId, int testSuite) {
		BasicDBObject query = new BasicDBObject("source_code_id", sourceCodeId);
		query.append("test_suite", testSuite);
		DBCursor cursor = coverage.find(query);
		
		if(cursor.size() > 0)
			return cursor;
		else {
//			logger.info("the size of cursor is 0 - source code id: " + sourceCodeId + " test suite: " + testSuite);
			cursor.close();
			return null;
		}
	}
	
	public DBCursor getDocumentsFromSuspiciousnes(){
		DBCursor cursor = suspiciousness_code.find();
		return cursor;
	}
	
	public void close(){
		this.mongo.close();
	}


}
